home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 2
/
Nebula Two.iso
/
SourceCode
/
GameKit
/
gamekit-1
/
GKStage.m
< prev
next >
Wrap
Text File
|
1995-06-12
|
7KB
|
229 lines
#import <gamekit/gamekit.h>
@interface GKStage(private)
- _add:adds remove:removes with:theList; // helper for -doAddsAndRemoves
@end
@implementation GKStage
- init
{
id ret = [super init];
int i;
for (i=0; i<=GK_ACTOR_TYPES; i++) {
actors[i] = [[List alloc] init];
addActors[i] = [[List alloc] init];
removeActors[i] = [[List alloc] init];
}
collisionGroups = [[List alloc] init];
addCollisionGroups = [[List alloc] init];
removeCollisionGroups = [[List alloc] init];
stageManager = nil;
return ret;
}
- makeDirtPileForBuffer:(int)anInt
{ // you can use anInt to tweak each DirtPile differently to get better speed
if (!anInt) return nil; // no DirtPile at level zero...
return [[[DirtPile alloc] init] setAllDirty];
}
- setBufferType:(int)anInt to:aBuffer
{
if ((anInt < 0) || (anInt > GK_BUFFER_TYPES)) return nil;
drawingBuffers[anInt] = aBuffer;
if (!anInt) return self; // no dirtpile #0...
if (!dirtPiles[anInt])
dirtPiles[anInt] = [self makeDirtPileForBuffer:anInt];
return self;
}
- dirtPileType:(int)anInt
{
if ((anInt < 0) || (anInt > GK_BUFFER_TYPES)) return nil;
return dirtPiles[anInt];
}
- bufferType:(int)anInt
{
if ((anInt < 0) || (anInt > GK_BUFFER_TYPES)) return nil;
return drawingBuffers[anInt];
}
- setStageManager:aManager { stageManager = aManager; return self; }
- stageManager { return stageManager; }
- actorListForType:(int)type
{
return actors[type];
}
- addActor:anActor ofType:(int)type
{ // hold on to it; we can't add while we're in the middle of a frame
// since it may affect the List object during a sweep of its contents
if ((type >= 0) && (type <= GK_ACTOR_TYPES))
[addActors[type] addObject:anActor];
return self;
}
- removeActor:anActor ofType:(int)type
{ // hold on to it; we can't remove while we're in the middle of a frame
// since it may affect the List object during a sweep of its contents
if ((type >= 0) && (type <= GK_ACTOR_TYPES))
[removeActors[type] addObject:anActor];
return self;
}
- addCollisionGroup:aGroup
{
[addCollisionGroups addObject:aGroup];
return self;
}
- removeCollisionGroup:aGroup
{
[removeCollisionGroups addObject:aGroup];
return self;
}
- collisionGroups { return collisionGroups; }
- findCollisionGroupWithTag:(int)anInt;
{
int i;
for (i=0; i<[collisionGroups count]; i++) {
id group = [collisionGroups objectAt:i];
if ([group tag] == anInt) return group;
}
return nil;
}
- _add:adds remove:removes with:theList level:(int)level
{
int j;
for (j=0; j<[adds count]; j++) {
id objectToAdd = [adds objectAt:j];
if (level >= 0) {
if ([objectToAdd respondsTo:@selector(setDrawingLevel:)])
[objectToAdd setDrawingLevel:level];
if ([objectToAdd respondsTo:@selector(setStage:)])
[objectToAdd setStage:self];
}
[theList addObject:objectToAdd];
}
for (j=0; j<[removes count]; j++) {
id anActor = [removes objectAt:j];
[theList removeObject:anActor];
[stageManager addDeadActor:anActor];
// if not using a manager, free the object...
if (!stageManager) [anActor free];
}
return self;
}
- doAddsAndRemoves
{ // _now_ it can take effect (actors at all levels and collision groups
int i;
for (i=0; i<=GK_ACTOR_TYPES; i++) {
[self _add:addActors[i] remove:removeActors[i] with:actors[i] level:i];
}
[self _add:addCollisionGroups remove:removeCollisionGroups
with:collisionGroups level:(-1)];
return self;
}
- doOneFrame
{
[self calculateMoves];
[self calculateCollisions];
if ([self doRender]) [self render];
[self doAddsAndRemoves];
return self;
}
- (BOOL)doRender { return YES; }
- calculateMoves
{
int i;
for (i=0; i<=GK_ACTOR_TYPES; i++) {
[actors[i] makeObjectsPerform:@selector(move:) with:self];
}
return self;
}
- calculateCollisions
{
[collisionGroups makeObjectsPerform:@selector(calculateCollisions:)
with:self];
return self;
}
- render
{
register int i, j, k, t, lastLevel = 0; // lastLevel is the number of the
// next lower buffer level. If a buffer doesn't exists, this allows us
// to skip it and use the next lowest (existing) buffer level.
// The actors will only move if the GameView is in the normal state
// and unpaused. They can still advance the render state machine, though.
BOOL shouldMove = ((![drawingBuffers[GK_SCREEN_BUFFER] isPaused]) &&
([drawingBuffers[GK_SCREEN_BUFFER] realGameState] == NORMALSTATE));
NXPoint offset;
[drawingBuffers[GK_SCREEN_BUFFER] getOffset:&offset];
// Loop through each buffer, allowing changes to propagate from
// the lowest to the highest buffer
for (i=1; i<GK_BUFFER_TYPES; i++) {
// Make sure that this buffer level exists; if not, we skip to the
// next level and push all actors in this level up to the next level.
if (drawingBuffers[i]) {
id thisDirtPile = nil;
// find the DirtPile for the next highest level. (If a level
// doesn't have a buffer, we need to effectively skip it.)
for (k=i+1; k<GK_BUFFER_TYPES; k++) { // if on last buffer,
// (top level) loop is skipped, and so thisDirtPile = nil
if (dirtPiles[k]) {
thisDirtPile = dirtPiles[k];
break;
} }
[drawingBuffers[i] lockFocus];
for (k=lastLevel+1; k<=i; k++) { // loop makes sure that any
// actors on a level w/o a buffer still get drawn and erased,
// but in the next higher buffer level.
// erase everything on this level by marking it dirty in
// the DirtPile for this level: each actor sends it's
// most recently drawn bounding box to the DirtPile.
[actors[k] makeObjectsPerform:@selector(eraseInDirtPile:)
with:dirtPiles[i]];
}
// Now, copy everything from the level below up to this level,
// using the DirtPile for efficiency. This makes all erasing
// happen at once.
[dirtPiles[i] sendDirtTo:thisDirtPile]; // next level needs to
// know of all changes on lower levels.
[dirtPiles[i] doRedraw:drawingBuffers[lastLevel]]; // go back
// to the most recent buffer
for (k=lastLevel+1; k<=i; k++) { // loop makes sure that any
// actors that are in a level w/o a buffer still get drawn,
// but in the next highest buffer level.
// Next draw anything that gets drawn at this level (any actors
// that are here.
t = [actors[k] count]; // faster than a message call each
// time thru the loop; requires that the list not change
// during the render, however!!!
for (j=0; j<t; j++) { // loop ourselves to be
// sure objects are called from #0 to highest; allows user
// to add actors in the order they are expected to be drawn
// (or sort the actors' drawing order)
[[actors[k] objectAt:j] renderAt:&offset
move:shouldMove withDirtPile:thisDirtPile];
} }
[drawingBuffers[i] unlockFocus];
lastLevel = i;
} }
return self;
}
@end